/**
 * SyntAttributes
 * --------------------------------------------------------------
 * 
 * - Is class will calculate the synthesized attributes.
 * 
 * - When a leaf node is reached, the path starts ascending, and values
 *   relation to restrictions on synthesized attributes are stored. 
 * 
 * @author 
 * @version 13-10-2013 
 */
package model.constraints.synthesized;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;

import model.constraints.inherited.Inters;

public class SyntAttributesXDF implements Cloneable {
	
	private ArrayList<String> contextList = new ArrayList<String>();
	private ArrayList<String> targetList = new ArrayList<String>();
	private ArrayList<String> keyList = new ArrayList<String>();
	
	private ArrayList<Boolean> c = new ArrayList<Boolean>(); //list true or false
	private String dc = new String(); // one data element
	private ArrayList<String> ds = new ArrayList<String>(); // one OR MORE data element
	private ArrayList<Inters> inters = new ArrayList<Inters>(); // list of tuples <l1, l2> l1 for DS and l2 for DC
	private String nodeName;	

	
	/**
	 * This function will join synthesized attributes with "inters" recovered
	 * @param aux is SyntAttributes
	 * @param htIntersXfd 
	 * @param dataPos
	 * @return
	 */
	public SyntAttributesXDF join (SyntAttributesXDF aux, Hashtable<String,ArrayList<Inters>> htIntersXfd, String dataPos) {	
		
		ArrayList<Inters> newInters;
		Inters inters1;
		Inters inters2;
		Inters inters1N, inters2N;
	
		if (this.getInters().isEmpty()) {
			newInters = aux.getInters();
		} else {
			
		   if (aux.getInters().isEmpty()) {
			   newInters = this.getInters();
		   } else {
				 newInters = new ArrayList<Inters>();				 
				 
				 // puts in newInters all intersections that are complete/calculated from syntattant  
				 for (Iterator<Inters> it1 = this.getInters().iterator(); it1.hasNext();){
					   
					 inters1 = it1.next();

					 if (!inters1.getDs().contains("#") && !inters1.getDc().equals("#"))
						   newInters.add(inters1);
					 else {
						 inters1N = new Inters(inters1);
						 
						 for (Iterator<Inters> it2 = aux.getInters().iterator(); it2.hasNext();){
							 inters2 = it2.next();
							 // System.out.println("Inters2 --> "+inters2.toString());   	
				  	    	   
						      for(int i=0;i<inters2.getDs().size();i++){
								    if (inters1.getDs().get(i).equals("#"))
			                               inters1N.setDs((String)inters2.getDs().get(i),i);    					
							  }
						      
						      if (inters1.getDc().equals("#"))
			                        inters1N.setDc(inters2.getDc());    					
						   
						      if (!containsEq(newInters,inters1N))
					    	       newInters.add(inters1N);
						   } 	
					 } 
				 } 	   
						   				   
				 // puts in newInters all intersections that are complete/calculated from syntatt  
				 for (Iterator<Inters> it2 = aux.getInters().iterator(); it2.hasNext();) {
					 
					   inters2 = it2.next();
					 
					   if (!inters2.getDs().contains("#") && !inters2.getDc().equals("#"))
						   newInters.add(inters2);
					   else { 	   
						
						   inters2N = new Inters(inters2);
		                   
						   for (Iterator<Inters> it1 = this.getInters().iterator(); it1.hasNext();) {
			  		              inters1 = it1.next();
			  		       
			  			          for(int i=0;i<inters2.getDs().size();i++) {
				  					    if (inters2.getDs().get(i).equals("#"))
				                                 inters2N.setDs((String)inters1.getDs().get(i),i);    					
			  			          }
				  			      
			  			          if (inters2.getDc().equals("#"))
			  			        	  inters2N.setDc(inters1.getDc());    					
			  			   
			  			          if (!containsEq(newInters,inters2N))
			  			        	  newInters.add(inters2N);
		                   } 	
		  	         } 
				 } 	         	         	        	       
	  	   	} 
		}    	    	   
	   
		if (!newInters.isEmpty()){
	       htIntersXfd.put(dataPos,newInters);
	    }   
	    
	    //System.out.println("Em join: htIntersXdf"+htIntersXfd.toString());
	    //System.out.println("new inters: "+newInters.toString());
	    
	    aux.inters = new ArrayList<Inters>();
		this.setInters(newInters);
		
		return this;
	}
	
	/***
	 * This function checks if has two inters equals
	 * @param newInters
	 * @param it
	 * @return if inters are equal return true
	 */
	public Boolean containsEq (ArrayList<Inters> newInters, Inters it) {
		
		for (Inters inter: newInters) {	     	  
			if (inter.getDs().equals(it.getDs()) && inter.getDc().equals(it.getDc()) )     	 
				return true;
		}    		  
	          
		return false;
	}	
	
	public void setDsSize(int size){
		ds = new ArrayList<String>(size);
		for(int i=0;i<size;i++)
			ds.add(i, "");
	}
	
	public void addC(boolean element){
		c.add(element);
	}
	
	public void addInters (Inters element){
		inters.add(element);
	}
		
	public void concatInters (ArrayList<Inters> element){
		for (Iterator<Inters> i = element.iterator(); i.hasNext();) {
			Inters c = i.next();
			inters.add(c);
		}
	}

	public void setDc(String element){
		dc = element;
	}
	
//	public void setDc(StringBuffer element){
//		dc.valueOf(element.toString());
//	}

	public void setDs(ArrayList<String> a){
		ds = a;
	}
	
	public void setC(ArrayList<Boolean> a){
		c = a;
	}
	
	public void setDs(String element, int position){
		ds.set(position, element);
	}

	public void setDs(StringBuffer element, int position){
		ds.set(position, element.toString());
	}
		
	public void setInters(ArrayList<Inters> element){
		inters = element;
	}
	
	public void setContextList(ArrayList<String> c) {
		contextList = c;
	}

	public ArrayList<String> getContextList() {
		return contextList;
	}

	public void addContextList(String s) {
		contextList.add(s);
	}

	public boolean containsContextList(String s) {
		if (contextList.contains(s))
			return true;
		
		return false;
	}

	public void clearContextList(){
		contextList.clear();
	}

	public int sizeContextList(){
		return contextList.size();
	}

	public void setTargetList(ArrayList<String> t){
		targetList = t;
	}

	public ArrayList<String> getTargetList(){
		return targetList;
	}

	public void addTargetList(ArrayList<String> al){
		targetList.addAll(al);
	}

	public int sizeTargetList(){
		return targetList.size();
	}

	public boolean containsTargetList(String s){
		if (targetList.contains(s))
			return true;
		
		return false;
	}

	public void setKeyList(ArrayList<String> k){
		keyList = k;
	}

	public ArrayList<String> getKeyList(){
		return keyList;
	}


	public void addKeyList(String s){
		keyList.add(s);
	}

	public boolean containsKeyList(String s){
		if (keyList.contains(s))
			return true;
		
		return false;
	}

	public int sizeKeyList(){
		return keyList.size();
	}

	public boolean isEmpty(){
		if (c.isEmpty() && ds.isEmpty() && inters.isEmpty() && dc.isEmpty())
			return true;
		else
			return false;
	}

	public void addAll(SyntAttributesXDF st){
		contextList.addAll(st.contextList);
		targetList.addAll(st.targetList);
		keyList.addAll(st.keyList);
	}

	public void addAllKey(SyntAttributesXDF st){
		keyList.addAll(st.keyList);
	}

	public void addAllTarget(SyntAttributesXDF st){
		targetList.addAll(st.targetList);
	}

	public void addAllContext(SyntAttributesXDF st){
		contextList.addAll(st.contextList);
	}
	
	public void setNodeName(String node){
		nodeName = node;
	}
	
	public String getNodeName(){
		return nodeName;
	}
	
	public String getDc(){
		return dc;
	}
	
	public ArrayList<String> getDs(){
		return ds;
	}
	
	public ArrayList<Inters> getInters(){
		return inters;
	}
	
	public ArrayList<Boolean> getC(){
		return c;
	}	

	public String toString(){
		StringBuffer strbuff = new StringBuffer();
		if(!ds.isEmpty())
			strbuff.append("ds = " + toStringAux(ds)+", ");
		if(!dc.isEmpty())
			strbuff.append("dc = <" + dc + ">, ");
		if(!inters.isEmpty())
			strbuff.append("inters = {" + toStringAux2(inters) + "}, ");
		if(!c.isEmpty())
			strbuff.append("c = " + toStringAux(c));
		
		String str = strbuff.toString();
		
		return str;
	}
	
	/**
	 * This function print ArrayList 
	 * @param ArrayList type Boolean or String
	 * @return String
	 */
	@SuppressWarnings("rawtypes")
	public String toStringAux(ArrayList list) {
		StringBuffer strbuff = new StringBuffer("<");
		
		for(int i=0;i<list.size();i++)
			strbuff.append(list.get(i).toString()).append(", ");
		
		strbuff.append(">");
		
		return strbuff.toString();
	}
	
	public String toStringAux2(ArrayList<Inters> list){
		StringBuffer strbuff = new StringBuffer();
		Inters aux;
		
		for(int i=0;i<list.size();i++) {
			aux = list.get(i);
			strbuff.append("<");
			//for(int j=0; j<aux.size();j++)
			strbuff.append(aux.getDs().toString()).append(", ");
			strbuff.append(aux.getDc().toString());
			strbuff.append(">, ");
		}
		
		return strbuff.toString();
	}
}